/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package functionroots.primitives;

/**
 *
 * @author orion
 */
public interface DerivableRealFunction extends RealFunction {

    public static final DerivableRealFunction absolute = new DerivableRealFunction() {

        @Override
        public double value(double x) {
            return Math.abs(x);
        }

        @Override
        public double derivative(double x) {
            if (x == 0) {
                throw new IllegalArgumentException("Função não definida no argumento dado: |" + x + "|.");
            } else if (x < 0) {
                return -1;
            } else {
                return 1;
            }
        }

        @Override
        public String text(double x) {
            return "|" + x + "|";
        }
    };
    public static final DerivableRealFunction base10Logarithm = new DerivableRealFunction() {

        @Override
        public double value(double x) {
            if (x <= 0) {
                throw new IllegalArgumentException("Função não definida no argumento dado:" + text(x) + ".");
            } else {
                return Math.log10(x);
            }
        }

        @Override
        public double derivative(double x) {
            if (x == 0) {
                throw new IllegalArgumentException("Função não definida no argumento dado: 1/(log(10) * " + x + ").");
            } else {
                return 1 / (Math.log(10) * x);
            }
        }

        @Override
        public String text(double x) {
            return "log10(" + x + ")";
        }
    };
    public static final DerivableRealFunction cubeRoot = new DerivableRealFunction() {

        @Override
        public double value(double x) {
            return Math.cbrt(x);
        }

        @Override
        public double derivative(double x) {
            return 1 / (3 * Math.cbrt(x * x));
        }

        @Override
        public String text(double x) {
            return "cbrt(" + x + ")";
        }
    };
    public static final DerivableRealFunction cossine = new DerivableRealFunction() {

        @Override
        public double value(double x) {
            return Math.cos(x);
        }

        @Override
        public double derivative(double x) {
            return -Math.sin(x);
        }

        @Override
        public String text(double x) {
            return "cos(" + x + ")";
        }
    };
    public static final DerivableRealFunction exponential = new DerivableRealFunction() {

        @Override
        public double value(double x) {
            return Math.exp(x);
        }

        @Override
        public double derivative(double x) {
            return Math.exp(x);
        }

        @Override
        public String text(double x) {
            return "exp(" + x + ")";
        }
    };
    public static final DerivableRealFunction logarithm  = new DerivableRealFunction() {

        @Override
        public double value(double x) {
            if (x <= 0) {
                throw new IllegalArgumentException("Função não definida no argumento dado:" + text(x) + ".");
            } else {
                return Math.log(x);
            }
        }

        @Override
        public double derivative(double x) {
            if (x == 0) {
                throw new IllegalArgumentException("Função não definida no argumento dado: 1/" + x + ".");
            } else {
                return 1 / x;
            }
        }

        @Override
        public String text(double x) {
            return "1/" + x;
        }
    };
    public static final DerivableRealFunction sine = new DerivableRealFunction() {

        @Override
        public double value(double x) {
            return Math.sin(x);
        }

        @Override
        public double derivative(double x) {
            return Math.cos(x);
        }

        @Override
        public String text(double x) {
            return "sin(" + x + ")";
        }
    };
    public static final DerivableRealFunction squareRoot  = new DerivableRealFunction() {

        @Override
        public double value(double x) {
            if (x < 0) {
                throw new IllegalArgumentException("Função não definida no argumento dado:" + text(x) + ".");
            } else {
                return Math.sqrt(x);
            }
        }

        @Override
        public double derivative(double x) {
            if (x < 0) {
                throw new IllegalArgumentException("Função não definida no argumento dado:" + text(x) + ".");
            } else {
                return 1 / (2 * Math.sqrt(x));
            }
        }

        @Override
        public String text(double x) {
            return "sqrt(" + x + ")";
        }
    };
    public static final DerivableRealFunction tangent = new DerivableRealFunction() {

        @Override
        public double value(double x) {
            return Math.tan(x);
        }

        @Override
        public double derivative(double x) {
            double y = Math.cos(x);
            if (y == 0) {
                throw new IllegalArgumentException("Função não definida no argumento dado: sec²(" + x + ").");
            }
            return 1 / (y * y);
        }

        @Override
        public String text(double x) {
            return "tan(" + x + ")";
        }
    };

    /**
     * Provides the calculation of the proposed function single-variable.
     * @param x The proposed function's argument.
     * @return The value of the implemented function on the given argument.
     * @throws IllegalArgumentException if the given argument does no belong to
     * the function's domain.
     */
    public double derivative(double x);

}
